package cn.org.wifit.core.zookeeper.watcher;

import java.util.List;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooKeeper;

import cn.org.wifit.core.zookeeper.NodeWriteDistributedTransactionWatcherHandle;

/**
 * 启动事件监听，为了保证在多个服务器一同启动的过程中，每台服务器都能正确的识别远程zookeeper节点的变化状态。
 * 所以要使用zookeeper的分布式事务所，保证每台服务器的启动是依次进行的。
 * @author yinwenjie
 *
 */
public class ServerBootWatcher implements Watcher {

	private String mySequence;
	
	private ZooKeeper zk;
	
	/**
	 * 业务处理对象
	 * IMServer启动时使用IMServerBootWatcherHandle；
	 * IMUser启动时使用IMUserBootWatcherHandle；
	 */
	private NodeWriteDistributedTransactionWatcherHandle bootWatcherHandle;
	
	public ServerBootWatcher() {
		
	}
	
	@Override
	public void process(WatchedEvent event) {
		/*
		 * 为了保证多台服务器启动时，服务器都是依次启动的，需要启动zookeeper的分布式事务管理
		 * 当boot节点下的serverboot节点发生变化时，事件被触发。
		 * 
		 * 当当前serverboot最小的Sequence号和mySequence号相等时，说明轮到自己启动了。
		 * 那么通知ServerBootWatcherHandle可以开始工作了，否则ServerBootWatcherHandle继续处于等待状态
		 * */
		if(event.getType() != EventType.NodeChildrenChanged) {
			return;
		}
		while(this.mySequence == null) {
			synchronized (this) {
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		if(!this.zk.getState().isConnected()) {
			return;
		}
		
		//取得目前zookeeper。boot目录下的所有节点
		boolean isMyTrun = false;
		String minSequence = null;
		try {
			List<String> bootServers =  this.zk.getChildren("/Boot", false);
			//取当前bootServers中的第一个，就是最小序号的节点了
			String bootServerFullPath = bootServers.get(0);
			minSequence = bootServerFullPath.substring(bootServerFullPath.length() - 10, bootServerFullPath.length());
			
			if(minSequence.equals(this.mySequence)) {
				isMyTrun = true;
			}
		} catch(Exception e) {
			e.printStackTrace(System.out);
		} finally {
			//无论怎样，都要重新建立对boot节点的监听
			try {
				this.zk.getChildren("/Boot", this);
			} catch (Exception e) {
				
			}
		}
		
		if(!isMyTrun) {
			System.out.println("正在等待远程编号为" + minSequence + "的服务器完成启动，请稍后。。。");
			return;
		}
		//=========这里通知ServerBootWatcherHandle进行启动处理
		try {
			System.out.println("该服务器正在向远程zookeeper集群注册节点信息。。。。");
			this.bootWatcherHandle.doHandle(mySequence, event.getPath());
		} catch(Exception e) {
			e.printStackTrace(System.out);
		}
		
		//启动完成后，移除这个节点代表的boot下的节点，以便让其他等待启动的服务器进行启动
		try {
			this.zk.close();
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
		
		System.out.println("服务器启动完成。。。。");
	}

	public ZooKeeper getZk() {
		return zk;
	}

	public void setZk(ZooKeeper zk) {
		this.zk = zk;
	}

	public String getMySequence() {
		return mySequence;
	}

	public void setMySequence(String mySequence) {
		this.mySequence = mySequence;
	}

	public NodeWriteDistributedTransactionWatcherHandle getBootWatcherHandle() {
		return bootWatcherHandle;
	}

	public void setBootWatcherHandle(
			NodeWriteDistributedTransactionWatcherHandle bootWatcherHandle) {
		this.bootWatcherHandle = bootWatcherHandle;
	}
}